package com.lei.study.depth.lock;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.RetryNTimes;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.Watcher;

import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;

/**
 * <p>
 * zk 客户端
 * </p>
 *
 * @author <a href="mailto:17674030991@163.com">伍磊</a>
 */
public class ZookeeperClient {

    /**
     * 分布式锁名称空间 zk-lock
     */
    private static final String ZK_LOCK_NAMESPACE = "zk-lock";

    /**
     * 根目录
     */
    private static final String ROOT_PATH = "/lock";

    /**
     * 数据前缀
     */
    private static final String DATA_PREFIX = "/node-";

    /**
     * 数据
     */
    private static final String DATA = ROOT_PATH + DATA_PREFIX;

    /**
     * 默认存储的节点值
     */
    public static final byte[] DEFAULT_VALUE_BYTES = "1".getBytes(StandardCharsets.UTF_8);


    private CuratorFramework client;

    private ZookeeperClient(CuratorFramework client) {
        this.client = client;
        this.client.start();
    }

    private static class ZookeeperClientHolder {

        private static ZookeeperClient zookeeperClient = new ZookeeperClient(
                CuratorFrameworkFactory.builder()
                        .namespace(ZK_LOCK_NAMESPACE)
                        .connectString("127.0.0.1:2181")
                        .connectionTimeoutMs(3000)
                        .sessionTimeoutMs(3000)
                        .retryPolicy(new RetryNTimes(3, 1000))
                        .build()
        );
    }

    public static ZookeeperClient getInstance() {
        return ZookeeperClientHolder.zookeeperClient;
    }

    /**
     * 创建节点信息
     *
     * @return 节点名称，不包含全路径
     * @throws Exception
     */
    public String createNode() throws Exception {
        String forPath = client.create().creatingParentsIfNeeded()
                .withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
                .forPath(DATA, DEFAULT_VALUE_BYTES);
        return forPath.substring(forPath.lastIndexOf("/") + 1);
    }

    /**
     * 添加监听节点
     *
     * @param path
     * @param watcher
     * @throws Exception
     */
    public void addWatch(String path, Watcher watcher) throws Exception {
        client.checkExists().usingWatcher(watcher).forPath(ROOT_PATH + "/" + path);
    }

    /**
     * 获取最小的节点名称
     *
     * @return
     * @throws Exception
     */
    public String getYoungestNode() throws Exception {
        List<String> children = getChildren();
        if (null != children && children.size() > 0) {
            return children.get(0);
        }
        return null;
    }

    /**
     * 删除节点
     *
     * @param curNodeName
     * @throws Exception
     */
    public void delNode(String curNodeName) throws Exception {
        client.delete().forPath(ROOT_PATH + "/" + curNodeName);
    }

    /**
     * 获取前一个节点名称
     *
     * @param currentNodeName
     * @return
     * @throws Exception
     */
    public String getPreNode(String currentNodeName) throws Exception {
        List<String> children = getChildren();
        int index = children.indexOf(currentNodeName);
        if (index >= 1) {
            return children.get(index - 1);
        }
        return null;
    }

    /**
     * 获取子节点
     *
     * @return
     */
    private List<String> getChildren() throws Exception {
        List<String> nodeList = client.getChildren().forPath(ROOT_PATH);
        Collections.sort(nodeList);
        return nodeList;
    }
}
